package cn.thoughtworks.school.services;

import cn.thoughtworks.school.entities.Organization;
import cn.thoughtworks.school.entities.User;
import cn.thoughtworks.school.entities.UserOrganization;
import cn.thoughtworks.school.entities.UserRole;
import cn.thoughtworks.school.entities.commands.CreateOrganizationCommand;
import cn.thoughtworks.school.entities.commands.CreateUserRoleCommand;
import cn.thoughtworks.school.exceptions.BusinessException;
import cn.thoughtworks.school.repositories.OrganizationRepository;
import cn.thoughtworks.school.repositories.UserOrganizationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class OrganizationService {

  @Autowired
  private OrganizationRepository organizationRepository;
  @Autowired
  private UserCenterService userCenterService;
  @Autowired
  private UserOrganizationRepository userOrganizationRepository;
  private final static Integer ADMIN_ROLE_NUMBER = 9;

  public List<Organization> findByUserId(Long userId) {
    return organizationRepository.findByUserId(userId);
  }

  public void addUsersToOrganizations(Long organizationId, List<Long> userIds) {
    List<Long> currentOrganizationUserIds = userOrganizationRepository.findByOrganizationIdAndUserIdIn(organizationId, userIds)
      .stream().map(UserOrganization::getUserId).collect(Collectors.toList());

    List<Long> needToAddUserIds = userIds.stream().filter(userId -> !currentOrganizationUserIds.contains(userId))
      .collect(Collectors.toList());

    List<UserOrganization> userOrganizations = needToAddUserIds.stream()
      .map(userId -> UserOrganization.build(organizationId, userId))
      .collect(Collectors.toList());
    userOrganizationRepository.saveAll(userOrganizations);
  }

  public List<UserOrganization> findUserOrganizationsByOrganizationId(Long organizationId) {
    return userOrganizationRepository.findByOrganizationId(organizationId);
  }

  public void addUserOrganization(UserOrganization userOrganization) {
    UserOrganization current = userOrganizationRepository.findByOrganizationIdAndUserId(userOrganization.getOrganizationId(), userOrganization.getUserId());
    if (Objects.isNull(current)) {
      userOrganizationRepository.save(userOrganization);
    }
  }

  public Page<Organization> findByPageable(Pageable pageable) {
    return organizationRepository.findAll(pageable);
  }

  public Organization createOrganization(CreateOrganizationCommand createOrganizationCommand, User user) {
    Organization organization = createOrganizationCommand.build(user.getId());
    return organizationRepository.save(organization);
  }

  public Organization updateOrganization(Long organizationId, Organization organization) throws BusinessException {
    Organization foundOrganization = organizationRepository.findById(organizationId).orElseThrow(
      () -> new BusinessException("Current organization is not exist.")
    );
    foundOrganization.update(organization);

    return organizationRepository.save(foundOrganization);
  }

  public Organization findById(Long organizationId) throws BusinessException {
    return organizationRepository.findById(organizationId).orElseThrow(
      () -> new BusinessException("Current organization is not exist")
    );
  }

  public List<UserRole> findOrganizationAdminsByOrganizationId(Long organizationId) {
    return userCenterService.findAdminsRoleByOrganizationId(organizationId);
  }

  public void deleteOrganizationAdminRole(Long organizationId, Long userId) {
    CreateUserRoleCommand createUserRoleCommand = new CreateUserRoleCommand(organizationId,userId,ADMIN_ROLE_NUMBER,"DELETE");
    userCenterService.updateUserRole(createUserRoleCommand);
  }

  public void addOrganizationAdminRole(CreateUserRoleCommand createUserRoleCommand) {
    createUserRoleCommand.setType("ADD");
    createUserRoleCommand.setRoleNumber(ADMIN_ROLE_NUMBER);
    userCenterService.updateUserRole(createUserRoleCommand);
  }
}
